package com.dfish.downloadtoolNew;

import java.io.IOException;
import java.net.DatagramSocket;
import java.net.SocketException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

import org.sipdroid.net.RtpPacket;
import org.sipdroid.net.RtpSocket;

import android.content.Context;
import br.com.voicetechnology.rtspclient.RTSPClient;
import br.com.voicetechnology.rtspclient.concepts.Client;
import br.com.voicetechnology.rtspclient.concepts.ClientListener;
import br.com.voicetechnology.rtspclient.concepts.Request;
import br.com.voicetechnology.rtspclient.concepts.Response;
import br.com.voicetechnology.rtspclient.transport.PlainTCP;

public class ReadRstpData implements ClientListener{
    private RTSPClient mClient;
    
    private List<String> resourceList;
    private int port;
    protected DatagramSocket udp_socket;
    private String controlURI;
    protected final int MTU = PlainTCP.mBufferSize;
    private boolean running = false;
    private boolean isTearDown = false;
    
    byte[] buffer = new byte[MTU];
    String uri;
    
    private Timer mTimer;
    private TimerTask mTimerTask;
    private Thread mReadThread;
    
    public ReadRstpData(Context context, String uri, int port) {
        this.port = port;
        this.uri = uri;
        
        mClient = new RTSPClient();
        mClient.setClientListener(this);
    }
    
    public void setupRtsp() {
        try {
            mClient.setTransport(new PlainTCP());
            mClient.describe(new URI(uri));
            resourceList = Collections.synchronizedList(new LinkedList<String>());
        } catch (IOException e) {
            e.printStackTrace();
        } catch (URISyntaxException e) {
            e.printStackTrace();
        }
        
        if (udp_socket == null || udp_socket.isClosed()) {
            try {
                udp_socket = new DatagramSocket(port);
                udp_socket.setSoTimeout(0);
            } catch (SocketException e) {
                e.printStackTrace();
            }
        }
    }
    
    public void restartDownload(String url) {
        this.uri = url;
        System.gc();
        startTimer();
    }
    
    private void startTimer() {
        if (mTimerTask == null) {
            mTimerTask = new TimerTask() {
                @Override
                public void run() {
                    if (isTearDown) {
                        setupRtsp();
                        isTearDown = false;
                        
                        if (mTimer != null) {  
                            mTimer.cancel();  
                            mTimer = null;  
                        }  
                  
                        if (mTimerTask != null) {  
                            mTimerTask.cancel();  
                            mTimerTask = null;  
                        } 
                    }
                }
            };
        }

        if (mTimerTask != null) {
            if (mTimer == null) {
                mTimer = new Timer();
            }
            
            try {
                mTimer.schedule(mTimerTask, 2000, 5000);
            } catch (IllegalStateException e) {
                if (mTimer != null) {  
                    mTimer.cancel();  
                    mTimer = null;  
                }  
          
                if (mTimerTask != null) {  
                    mTimerTask.cancel();  
                    mTimerTask = null;  
                } 
            }
        }
    }
    
    public void closeRtsp() throws InterruptedException {
        running = false;
        
        if (mReadThread != null && !mReadThread.isInterrupted()) {
            mReadThread.interrupt();
            mReadThread = null;
            System.gc();
        }
        
        if (mClient != null) {
            mClient.teardown();
        }
        DDebug.logd("closeRtsp running=" + running);
    }

    private void do_stream() {
        RtpPacket rtp_packet = new RtpPacket(buffer, MTU);
        RtpSocket rtp_socket = new RtpSocket(udp_socket);
        
        while (running) {
            //Log.d(TAG, "do_stream running=" + running);
            try {
                if (udp_socket != null && !udp_socket.isClosed()) {
                    rtp_socket.receive(rtp_packet);
//                    synchronized (MainActivity.lock) {
                        MainActivity.mDownloadData += rtp_packet.getLength();
//                    }
                } else {
                    if (mClient != null) {
                        mClient.teardown();
                    }
                    break;
                }
                
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    
    @Override
    public void generalError(Client client, Throwable error) {
        error.printStackTrace();
    }

    @Override
    public void mediaDescriptor(Client client, String descriptor) {
        final String target = "control:";
        System.out.println("Session Descriptor\n" + descriptor);
        int position = -1;
        while ((position = descriptor.indexOf(target)) > -1) {
            descriptor = descriptor.substring(position + target.length());
            resourceList.add(descriptor.substring(0, descriptor.indexOf('\r')));
        }
    }

    @Override
    public void requestFailed(Client client, Request request, Throwable cause) {
        cause.printStackTrace();
    }

    @Override
    public void response(Client client, Request request, Response response) {
        
        try {
            //synchronized (MainActivity.lock) {
            MainActivity.mDownloadData += response.getBytes().length;
            //}
            if (response.getStatusCode() == 200) {
                switch (request.getMethod()) {
                case DESCRIBE:
                    if (resourceList.get(0).equals("*")) {
                        controlURI = request.getURI();
                        resourceList.remove(0);
                    }
                    if (resourceList.size() > 0) {
                        client.setup(new URI(controlURI), nextPort(),
                                resourceList.remove(0));
                        DDebug.logd("DESCRIBE client.setup > 0");
                    } else {
                        client.setup(new URI(controlURI), nextPort());
                        DDebug.logd("DESCRIBE client.setup <= 0");
                    }
                    break;
                case SETUP:
                    // sets up next session or ends everything.
                    if (resourceList.size() > 0) {
                        client.setup(new URI(controlURI), nextPort(),
                                resourceList.remove(0));
                        DDebug.logd("SETUP client.setup > 0");
                    } else {
                        client.play();  
                    }
                    break;
                case PLAY:
                    running = false;
                    if (mReadThread != null && !mReadThread.isInterrupted()) {
                        mReadThread.interrupt();
                        mReadThread = null;
                    }
                    mReadThread = new Thread() {
                        public void run() {
                            running = true;
                            do_stream();
                        }
                    };
                    mReadThread.start();
                    break;
                case TEARDOWN:
                    udp_socket.close();
                    isTearDown = true;
                    break;
                default:
                    break;
                }
                DDebug.logd(response.toString());
            } else {
                client.teardown();
                udp_socket.close();                
                isTearDown = true;
                startTimer();
                
                DDebug.logd( "error" + response.toString());
            }
        } catch (Throwable t) {
            generalError(client, t);
            
            client.teardown();
            udp_socket.close();
            udp_socket = null;
            isTearDown = true;
            startTimer();
        }
    }    
    
    protected void sessionSet(Client client) throws IOException {
        client.play();
    }
    
    private int nextPort() {
        //return (port += 2) - 2;
        return port;
    }
}
